#include<iostream>
#include<sys/epoll.h>
#include<unistd.h>
#include"sock.hpp"
#include<string>
using namespace std;
#define NUM 64
void Usage(string proc)
{
  cout<<"Usage: "<<proc<<" port"<<endl;
}

int main(int argc, char* argv[])
{
  if(argc!=2)
  {
    Usage(argv[0]);
    exit(1);
  }
  //1.建立tcp，监听socket
  uint16_t port = (uint16_t)atoi(argv[1]);
  int listen_sock =  Sock::Socket();
 // cout<<listen_sock<<endl;
  Sock::Bind(listen_sock,port);
  Sock::Listen(listen_sock);

  //2.创建epoll 模型，获得epfd(文件描述符)
  int epfd = epoll_create(128);

  //3.先添加listen_sock和他所关心的事件添加到内核
  struct epoll_event ev;
  ev.events = EPOLLIN|EPOLLET;
  ev.data.fd = listen_sock;
  epoll_ctl(epfd, EPOLL_CTL_ADD,listen_sock,&ev);

  //4.事件循环

  volatile bool quit = false;
  struct  epoll_event revs[NUM];
  while(!quit)
  {
    int timeout=-1;//阻塞等待就绪
    // 这里传入的数组，仅仅是尝试从内核中拿回来已经就绪的事件
    int n = epoll_wait(epfd, revs,NUM,timeout);
    switch(n)
    {
      case 0:
        cout<<"timeout..."<<endl;
        break;
      case -1:
        cout<<"epoll error"<<endl;
        break;
      default:
        cout<<" 有事件就绪了"<<endl;
        //5 处理就绪事件
        for(int i =0;i<n;i++)
        {

          int sock = revs[i].data.fd;
          cout<<"文件描述符： "<<sock<<" 上面有事件就绪了"<<endl;
          if(revs[i].events&EPOLLIN)
          {
            cout<<"文件描述符： "<<sock<<"读事件就绪"<<endl;
            //5.1 处理链接事件
            if(sock==listen_sock)
            {  
              cout<<"文件描述符： "<<sock<<"链接事件就绪"<<endl;
             // int fd = Sock::Accept(listen_sock); 
             // if(fd>=0) 
             // {
             //    //获取成功
             //   cout<<"获取新链接成功了： "<<fd<<endl;
             //   struct epoll_event _ev;
             //   _ev.events = EPOLLIN;
             //   _ev.data.fd = fd;
             //   epoll_ctl(epfd, EPOLL_CTL_ADD,fd,&_ev);//新的fd托管给epoll               
             //   cout<<"已经将fd"<<fd<<" 托管给epoll了"<<endl;
             // }
           //  else 
           //   {
           //     //Do Nothing!!
           //   }
            }
            //5.2 处理正常读取事件
            else 
            {
              cout<<"正常事件就绪"<<endl;
              char buffer[1024];
              ssize_t s= recv(sock,buffer, sizeof(buffer)-1,0);
              if(s>0)
              {
                buffer[s]='\0';
                cout<<"client ["<<sock<<"]# "<<buffer<<endl;
                //将我们关心的事件改成EPOLLOUT
              //  struct epoll_event _ev;
              //  _ev.events = EPOLLOUT;
              //  _ev.data.fd = sock;
              //  epoll_ctl(epfd,EPOLL_CTL_MOD,sock,&_ev);
              }
              else if(s==0)
              {
                cout<<"对端关闭了链接"<<endl;
                close(sock);
                epoll_ctl(epfd,EPOLL_CTL_DEL,sock,nullptr);//删除已经关闭的关心的事件
                cout<<"sock: "<<sock<<"delete from epoll success"<<endl;

              }
              else 
              {
                //读取失败
                close(sock);       
                epoll_ctl(epfd,EPOLL_CTL_DEL,sock,nullptr);//删除已经关闭的关心的事件
                cout<<"sock: "<<sock<<"delete from epoll success"<<endl;
              }
            }
          }
          else if (revs[i].events&EPOLLOUT) 
          {
            //处理写事件
            
          }

          else 
          {

          }
        }
        break;
    }
  }


  close(epfd);
  close(listen_sock);
  return 0;
}

